package com.ruoyi.service.impl;

import com.ruoyi.config.sharding.ShardingTableUtils;
import com.ruoyi.domain.DeviceData;
import com.ruoyi.service.DeviceDataShardingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class DeviceDataShardingServiceImp implements DeviceDataShardingService {
    @Autowired
    private ShardingTableUtils shardingTableUtils;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 保存设备数据到对应的分表
     */
    public void saveDeviceData(DeviceData data) {
        LocalDate date = Optional.ofNullable(data.getCollectTime())
                .map(LocalDateTime::toLocalDate)
                .orElse(LocalDate.now());
        String tableName = shardingTableUtils.getShardingTableName(
                "device_data", date, ShardingTableUtils.ShardingType.DAILY);
        // 检查表是否存在，不存在则创建
        if (!shardingTableUtils.tableExists(tableName)) {
            shardingTableUtils.createTableFromBase("device_data", tableName);
        }
        // 执行插入操作
        shardingTableUtils.executeInsert(data, tableName);
    }

    /**
     * 查询指定日期范围内的设备数据
     */
    public List<DeviceData> getDeviceDataByDateRange(LocalDate startDate, LocalDate endDate) {
        List<DeviceData> result = new ArrayList<>();

        // 获取日期范围内的所有表名
        List<String> tableNames = shardingTableUtils.getShardingTableNamesInRange(
                "device_data", startDate, endDate, ShardingTableUtils.ShardingType.DAILY);

        // 遍历所有表，查询数据
        for (String tableName : tableNames) {
            if (shardingTableUtils.tableExists(tableName)) {
                String sql = "SELECT * FROM `" + tableName + "` " +
                        "WHERE collect_time BETWEEN ? AND ?";

                List<DeviceData> dataList = jdbcTemplate.query(sql,
                        new Object[] {
                                Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()),
                                Date.from(endDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant())
                        },
                        (rs, rowNum) -> {
                            DeviceData data = new DeviceData();
                            data.setId(rs.getInt("id"));
                            data.setClientId(rs.getString("clientId"));
                            data.setVersion(rs.getString("version"));
                            data.setTemperature(rs.getDouble("temperature"));
                            data.setHumidity(rs.getDouble("humidity"));
                            data.setSensorId(rs.getString("sensorId"));
                            data.setCollectTime(rs.getTimestamp("collectTime").toLocalDateTime());
                            return data;
                        });
                result.addAll(dataList);
            }
        }
        return result;
    }

    /**
     * 查询指定日期前最近的N条设备数据记录
     */
    public List<DeviceData> getLatestDeviceDataBeforeDate(LocalDate date, int limit, String sensorId) {
        // 查询指定日期前的记录，最多检查3个表
        List<Map<String, Object>> records = shardingTableUtils.queryLatestRecordsByDate(
                "device_data", limit, ShardingTableUtils.ShardingType.DAILY, 3, date, sensorId);
        // 将Map转换为DeviceData对象
        return records.stream()
                .map(record -> {
                    DeviceData data = new DeviceData();
                    data.setId((Integer) record.get("id"));
                    data.setClientId((String) record.get("client_id"));
                    data.setVersion((String) record.get("version"));
                    data.setTemperature((Double) record.get("temperature"));
                    data.setHumidity((Double) record.get("humidity"));
                    data.setSensorId((String) record.get("sensor_id"));
                    data.setCollectTime((LocalDateTime) record.get("collect_time"));
                    return data;
                })
                .collect(Collectors.toList());
    }

}